#include "FileSys.h"

#include <stdio.h>

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QStandardPaths>

FileSys::FileSys() {
  Q_ASSERT_X(qApp, "FileSys Construction!", "QApplication should be there!");
  if (qApp) m_exeDir = QCoreApplication::applicationDirPath();

  m_appName = QCoreApplication::applicationName();
  m_userId = "Taurus";
}

FileSys* FileSys::instance() {
  static FileSys s_instance;
  return &s_instance;
}

QString FileSys::runRootDir() const { return m_exeDir; }

QString FileSys::dataDir() const {
#ifdef WIN32
  return m_exeDir;
#else
  return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
#endif
}

QString FileSys::appCfgDir() const { return m_exeDir + "/config"; }

QString FileSys::writeableAppCfgDir() const {
#ifdef WIN32
  return appCfgDir();
#else
  QString path = dataDir();
  if (path.isEmpty()) {
    log_warning("Cant find writeableAppCfgDir!");
    return appCfgDir();
  }

  return path + "/config";
#endif
}

QString FileSys::logDir() const {
#ifdef WIN32
  return m_exeDir + "/logs";
#else
  QString path = dataDir();
  if (path.isEmpty()) {
    log_warning("Cant find logDir!");
    return m_exeDir + "/logs";
  }

  return path + "/logs";
#endif
}

QString FileSys::userCfgDir() const {
#ifdef WIN32
  return m_exeDir + "/config/User/" + m_userId;
#else
  QString path = dataDir();
  if (path.isEmpty()) {
    log_warning("Cant find userCfgDir!");
    return m_exeDir + "/config/User/" + m_userId;
  }

  return path + "/config/User/" + m_userId;
#endif
}

QString FileSys::tmpDir() const {
#ifdef WIN32
  return m_exeDir + "/temp";
#else
  QString path = dataDir();
  if (path.isEmpty()) {
    log_warning("Cant find tmpDir!");
    return m_exeDir + "/temp";
  }

  return path + "/temp";
#endif
}

bool FileSys::createFile(const QString& fullFileName,
                         QIODevice::OpenModeFlag flag, QFile*& file) const {
  QFileInfo fi(fullFileName);
  fi.absoluteDir().mkpath(fi.absolutePath());

  file = new QFile(fullFileName);
  if (file->open(flag)) return true;

  delete file;
  file = nullptr;
  return false;
}

bool FileSys::closeFile(QFile* file) const {
  if (file) {
    file->close();
    delete file;
    file = nullptr;

    return true;
  }

  return false;
}

int64_t FileSys::getFileSize(QFile* file) const {
  if (!file) {
    return 0;
  }
  return file->size();
}

int64_t FileSys::readFile(QFile* file, char* data, int64_t maxlen) {
  if (!file) {
    return 0;
  }
  return file->read(data, maxlen);
}

int FileSys::copyFile(const char* src, const char* des) {
  int nRet = 0;
  FILE *pSrc = nullptr, *pDes = nullptr;
#ifdef _MSC_VER
  errno_t errSrc = fopen_s(&pSrc, src, "r");
  errno_t errDes = fopen_s(&pDes, des, "w+");
#else
  pSrc = fopen(src, "r");
  pDes = fopen(des, "w+");
#endif

  if (pSrc && pDes) {
    int nLen = 0;
    char szBuf[1024] = {0};
    while ((nLen = fread(szBuf, 1, sizeof szBuf, pSrc)) > 0) {
      fwrite(szBuf, 1, nLen, pDes);
    }
  } else
    nRet = -1;

  if (pSrc) fclose(pSrc), pSrc = nullptr;

  if (pDes) fclose(pDes), pDes = nullptr;

  return nRet;
}

bool FileSys::removeFile(const QString& fullFileName) const {
  if (fullFileName.isEmpty()) return true;
  return QFile::remove(fullFileName);
}

bool FileSys::isFileExist(const QString& fullFileName) const {
  QFile file(fullFileName);
  return file.exists();
}

bool FileSys::isFileWritable(const QString& fullFileName) const {
  QFile file(fullFileName);
  QFileInfo fileInfo(file);

  if (!file.open(QIODevice::ReadWrite)) {
    return false;
  }

  return fileInfo.isWritable();
}

bool FileSys::makePathExist(const QString& path) const {
  QDir dir;
  return dir.mkpath(path);
}

void FileSys::makeSlashPath(qb::base::BaseString& path) {
  if (path.size() > 0) {
    if (path.at(path.size() - 1) != '\\' && path.at(path.size() - 1) != '/')
      path.push_back('\\');
  }
}

qb::base::BaseString FileSys::getSlashPath(const char* path) {
  qb::base::BaseString slashp = path;
  makeSlashPath(slashp);
  return slashp;
}

std::string FileSys::makeFullDataPath(const std::string& path) {
  std::string fullPath = path;
  QFileInfo fi(QString::fromStdString(path));
  if (!fi.isAbsolute()) {
    fullPath = dataDir().toStdString();
    if (path[0] == '/')
      fullPath += path;
    else
      fullPath += "/" + path;
  }

  return fullPath;
}